package com.tanhua.manage.service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tanhua.manage.domain.Admin;
import com.tanhua.manage.domain.AnalysisByDay;
import com.tanhua.manage.domain.Count;
import com.tanhua.manage.mapper.AdminMapper;
import com.tanhua.manage.mapper.AnalysisByDayMapper;
import com.tanhua.manage.mapper.LogMapper;
import com.tanhua.manage.utils.ComputeUtil;
import com.tanhua.manage.utils.Retention1dUtil;
import com.tanhua.manage.vo.AnalysisSummaryVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

@Service
public class AnalysisByDayService extends ServiceImpl<AnalysisByDayMapper, AnalysisByDay> {
    // 操作日表的mapper
    @Autowired
    private AnalysisByDayMapper analysisByDayMapper;
    // 查询日志表的mapper
    @Autowired
    private LogMapper logMapper;

    /**
     * 接口名称：概要统计信息
     *
     * @return
     */
    public ResponseEntity<Object> summary() {

        // 1. 查询累计用户 SELECT SUM(num_registered) num_registered FROM tb_analysis_by_day
        AnalysisByDay analysisByDay = query().select("SUM(num_registered) numRegistered").one();
        // 获取累计用户
        Integer numRegistered = analysisByDay.getNumRegistered();

        // 2. 查询今日新增、登陆次数、活跃用户
        // SELECT num_registered FROM tb_analysis_by_day WHERE record_date='2021-05-16'
        Date date = new Date();
        String today = new SimpleDateFormat("yyyy-MM-dd").format(date);
        AnalysisByDay todayAnalysis = query().eq("record_date", today).one();
        // 获取今日新增、登陆次数、活跃用户
        Integer todayRegistered = todayAnalysis.getNumRegistered();
        Integer todayNumLogin = todayAnalysis.getNumLogin();
        Integer todayNumActive = todayAnalysis.getNumActive();

        //3. 查询昨日新增、登陆次数、活跃用户
        // 获取昨天日期  2021-05-15
        String yes = ComputeUtil.offsetDay(date, -1);
        AnalysisByDay yesAnalysis = query().eq("record_date", yes).one();
        // 获取昨日新增、登陆次数、活跃用户
        Integer yesRegistered = yesAnalysis.getNumRegistered();
        Integer yesNumLogin = yesAnalysis.getNumLogin();
        Integer yesNumActive = yesAnalysis.getNumActive();

        //4. 过去30天活跃用户数和过去7天活跃用户
        //4.1 过去7天活跃用户
        // SELECT SUM(num_active) numActive FROM tb_analysis_by_day WHERE record_date BETWEEN '2021-04-16' AND '2021-05-16'
        AnalysisByDay day7 = query().between("record_date", ComputeUtil.offsetDay(date, -7), today)
                .select("SUM(num_active) numActive").one();
        AnalysisByDay day30 = query().between("record_date", ComputeUtil.offsetDay(date, -30), today)
                .select("SUM(num_active) numActive").one();

        // 返回的结果
        AnalysisSummaryVo vo = new AnalysisSummaryVo();
        // 设置累计用户
        vo.setCumulativeUsers(numRegistered.longValue());
        // 今日新增、登陆次数、活跃用户
        vo.setNewUsersToday(todayRegistered.longValue());
        vo.setLoginTimesToday(todayNumLogin.longValue());
        vo.setActiveUsersToday(todayNumActive.longValue());
        // 环比涨跌率
        vo.setNewUsersTodayRate(ComputeUtil.computeRate(todayRegistered, yesRegistered));
        vo.setLoginTimesTodayRate(ComputeUtil.computeRate(todayNumLogin, yesNumLogin));
        vo.setActiveUsersTodayRate(ComputeUtil.computeRate(todayNumActive, yesNumActive));
        // 过去30天活跃用户数和过去7天活跃用户
        vo.setActivePassWeek(day7.getNumActive().longValue());
        vo.setActivePassMonth(day30.getNumActive().longValue());

        return ResponseEntity.ok(vo);
    }

    /**
     * 统计日志表数据并更新到日表中
     */
    public void analysis() {

        // 1.获取今天时间
        Date date = new Date();
        String today = DateUtil.formatDate(date);

        // 2.根据今天日期查询日表，如果没有查到数据，执行添加
        QueryWrapper<AnalysisByDay> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("record_date", today);
        AnalysisByDay analysisByDay = analysisByDayMapper.selectOne(queryWrapper);
        if (analysisByDay == null) {
            // tb_analysis_by_day 日表中没有今天的统计数据，执行添加
            analysisByDay = new AnalysisByDay();
            analysisByDay.setRecordDate(new Date());
            analysisByDay.setCreated(new Date());
            analysisByDay.setUpdated(new Date());
            // 添加
            analysisByDayMapper.insert(analysisByDay);
        }

        // 3. 查询日志表
        // 3.1 查询日志表 新注册用户
        Long numRegister = logMapper.queryNumsByType(today, "0102");
        // 3.2 查询日志表 登陆次数
        Long numLogin = logMapper.queryNumsByType(today, "0101");
        // 3.3 查询日志表 活跃用户
        Long numActive = logMapper.queryNumsByDate(today);
        // 3.4 查询日志表 次日留存
        Long numRetention1d = logMapper.queryRetention1d(today, ComputeUtil.offsetDay(date, -1));

        // 4.日表中已经有今天的统计数据，执行更新
        analysisByDay.setNumRegistered(numRegister.intValue());
        analysisByDay.setNumActive(numActive.intValue());
        analysisByDay.setNumLogin(numLogin.intValue());
        analysisByDay.setNumRetention1d(numRetention1d.intValue());
        // 更新日表
        analysisByDayMapper.updateById(analysisByDay);
    }

    /**
     * 接口名称：新增、活跃用户、次日留存率
     */
    public ResponseEntity<Object> countUsers(Long sd, Long ed, Integer type) throws ParseException {

        List<Map> thisYear = this.countThisYear(sd, ed, type);
        List<Map> lastYear = this.countLastYear(sd, ed, type);

        // 封装数据返回
        Count count = new Count();
        count.setThisYear(thisYear);
        count.setLastYear(lastYear);

        return ResponseEntity.ok(count);
    }

    /**
     * 统计今年的用户数据
     *
     * @return
     */
    private List<Map> countThisYear(Long sd, Long ed, Integer type) throws ParseException {

        // 开始时间
        Date startDate = new Date(sd);
        // 结束时间
        Date endDate = new Date(ed);
        // 创建Calendar对象
        Calendar cal = Calendar.getInstance();
        cal.setTime(startDate);

        // 循环读取数据
        Map<String, Object> map = null;
        List<Map> list = new ArrayList<>();
        while (cal.getTime().getTime() <= endDate.getTime()) {
            map = new HashMap<>();
            // 查询条件
            QueryWrapper<AnalysisByDay> wrapper = new QueryWrapper<>();
            wrapper.eq("record_date", new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime()));
            // 查数据
            AnalysisByDay analysisByDay = analysisByDayMapper.selectOne(wrapper);
            // 封装
            map.put("title", new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime()));
            switch (type) {
                // 新增
                case 101:
                    map.put("amount", analysisByDay.getNumRegistered());
                    cal.add(Calendar.DAY_OF_MONTH, 1);
                    break;
                // 活跃
                case 102:
                    map.put("amount", analysisByDay.getNumActive());
                    cal.add(Calendar.DAY_OF_MONTH, 1);
                    break;
                // 次日留存率
                case 103:
                    cal.add(Calendar.DAY_OF_MONTH, -1);
                    QueryWrapper<AnalysisByDay> yesWrapper = new QueryWrapper<>();
                    yesWrapper.eq("record_date", new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime()));
                    AnalysisByDay yesData = analysisByDayMapper.selectOne(yesWrapper);
                    Integer numRetention1d = analysisByDay.getNumRetention1d();
                    Integer numRegistered = yesData.getNumRegistered();
                    // 工具类计算次日留存率
                    Double result = Retention1dUtil.calRetention1d(numRegistered, numRetention1d);
                    map.put("amount", result);
                    cal.add(Calendar.DAY_OF_MONTH, 2);
                    break;
            }
            // 加入集合
            list.add(map);
        }

        return list;
    }

    /**
     * 统计去年的用户数据
     *
     * @return
     */
    private List<Map> countLastYear(Long sd, Long ed, Integer type) throws ParseException {

        // 开始时间
        Date startDate = new Date(sd);
        // 结束时间
        Date endDate = new Date(ed);
        // 创建Calendar对象
        // 去年起始
        Calendar thisCal = Calendar.getInstance();
        thisCal.setTime(startDate);
        thisCal.add(Calendar.YEAR, -1);
        // 去年结束
        Calendar lastCal = Calendar.getInstance();
        lastCal.setTime(endDate);
        lastCal.add(Calendar.YEAR, -1);

        // 循环读取数据
        Map<String, Object> map = null;
        List<Map> list = new ArrayList<>();
        while (thisCal.getTime().getTime() <= lastCal.getTime().getTime()) {
            map = new HashMap<>();
            // 查询条件
            QueryWrapper<AnalysisByDay> wrapper = new QueryWrapper<>();
            wrapper.eq("record_date", new SimpleDateFormat("yyyy-MM-dd").format(thisCal.getTime()));
            // 查数据
            AnalysisByDay analysisByDay = analysisByDayMapper.selectOne(wrapper);
            // 封装
            map.put("title", new SimpleDateFormat("yyyy-MM-dd").format(thisCal.getTime()));
            switch (type) {
                // 新增
                case 101:
                    map.put("amount", analysisByDay.getNumRegistered());
                    thisCal.add(Calendar.DAY_OF_MONTH, 1);
                    break;
                // 活跃
                case 102:
                    map.put("amount", analysisByDay.getNumActive());
                    thisCal.add(Calendar.DAY_OF_MONTH, 1);
                    break;
                // 次日留存率
                case 103:
                    thisCal.add(Calendar.DAY_OF_MONTH, -1);
                    QueryWrapper<AnalysisByDay> yesWrapper = new QueryWrapper<>();
                    yesWrapper.eq("record_date", new SimpleDateFormat("yyyy-MM-dd").format(thisCal.getTime()));
                    AnalysisByDay yesData = analysisByDayMapper.selectOne(yesWrapper);
                    Integer numRetention1d = analysisByDay.getNumRetention1d();
                    Integer numRegistered = yesData.getNumRegistered();
                    // 工具类计算次日留存率
                    Double result = Retention1dUtil.calRetention1d(numRegistered, numRetention1d);
                    map.put("amount", result);
                    thisCal.add(Calendar.DAY_OF_MONTH, 2);
                    break;
            }
            // 加入集合
            list.add(map);
        }

        return list;
    }
}